//
//  TITokenField.m
//  TITokenField
//
//  Created by Tom Irving on 16/02/2010.
//  Copyright 2012 Tom Irving. All rights reserved.
//

#import "TITokenField.h"
#import <QuartzCore/QuartzCore.h>
#import "IStarTools.h"

@interface TITokenField ()
@property (nonatomic, assign) BOOL forcePickSearchResult;
@property (nonatomic, assign) BOOL alwaysShowSearchResult;
@end

//==========================================================
#pragma mark - TITokenFieldView -
//==========================================================

@interface TITokenFieldView (Private)
- (void)setup;
- (NSString *)displayStringForRepresentedObject:(id)object;
- (NSString *)searchResultStringForRepresentedObject:(id)object;
- (void)setSearchResultsVisible:(BOOL)visible;
- (void)resultsForSearchString:(NSString *)searchString;
@end

static const CGFloat defaultHeight = 100;//默认高度

@implementation TITokenFieldView {
    NSMutableArray * _resultsArray;
}
@dynamic delegate;
@synthesize showAlreadyTokenized = _showAlreadyTokenized;
@synthesize searchSubtitles = _searchSubtitles;
@synthesize subtitleIsPhoneNumber = _subtitleIsPhoneNumber;
@synthesize forcePickSearchResult = _forcePickSearchResult;
@synthesize alwaysShowSearchResult = _alwaysShowSearchResult;
@synthesize shouldSortResults = _shouldSortResults;
@synthesize shouldSearchInBackground = _shouldSearchInBackground;
//@synthesize permittedArrowDirections = _permittedArrowDirections;
@synthesize tokenField = _tokenField;
@synthesize sourceArray = _sourceArray;
#pragma mark Init
- (instancetype)initWithFrame:(CGRect)frame {
    
    if ((self = [super initWithFrame:frame])){
        [self setup];
    }
    
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    
    if ((self = [super initWithCoder:aDecoder])){
        [self setup];
    }
    
    return self;
}

- (void)setup {
    
    [self setBackgroundColor:[UIColor clearColor]];
    [self setDelaysContentTouches:NO];
    [self setMultipleTouchEnabled:NO];
    self.scrollEnabled = YES;
    
    _showAlreadyTokenized = NO;
    _searchSubtitles = YES;
    _subtitleIsPhoneNumber = NO;
    _forcePickSearchResult = NO;
    _alwaysShowSearchResult = NO;
    _shouldSortResults = YES;
    _shouldSearchInBackground = NO;
//    _permittedArrowDirections = UIPopoverArrowDirectionUp;
    _resultsArray = [NSMutableArray array];
    
    _tokenField = [[TITokenField alloc] initWithFrame:CGRectMake(0, 0, SCREENWIDTHISTAR, defaultHeight)];
    //_tokenField.backgroundColor = [UIColor greenColor];
    _tokenField.font = [UIFont systemFontOfSize:16];
    [_tokenField addTarget:self action:@selector(tokenFieldDidBeginEditing:) forControlEvents:UIControlEventEditingDidBegin];
    [_tokenField addTarget:self action:@selector(tokenFieldDidEndEditing:) forControlEvents:UIControlEventEditingDidEnd];
    [_tokenField addTarget:self action:@selector(tokenFieldTextDidChange:) forControlEvents:UIControlEventEditingChanged];
    [_tokenField addTarget:self action:@selector(tokenFieldFrameWillChange:) forControlEvents:(UIControlEvents)TITokenFieldControlEventFrameWillChange];
    [_tokenField addTarget:self action:@selector(tokenFieldFrameDidChange:) forControlEvents:(UIControlEvents)TITokenFieldControlEventFrameDidChange];
    [_tokenField setDelegate:self];
    [self addSubview:_tokenField];
    
    //CGFloat tokenFieldBottom = CGRectGetMaxY(_tokenField.frame);
    
    [self bringSubviewToFront:_tokenField];
    [self updateContentSize];
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}


- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated{
    
}

- (BOOL)touchesShouldCancelInContentView:(UIView *)view{
    return YES;
}

- (BOOL)tokenField:(TITokenField *)tokenField willAddToken:(TIToken *)token{
    BOOL shouldAdd = YES;
    if(self.tokenField){
//        [self.tokenField.tokens enumerateObjectsUsingBlock:^(TIToken  * obj, NSUInteger idx, BOOL * stop) {
//            if([obj.title isEqualToString:token.title]){
//                //相同的不添加
//                shouldAdd = NO;
//                stop = YES;
//            }
//        }];
        for (TIToken * obj in self.tokenField.tokens) {
            if([obj.title isEqualToString:token.title]) {
                shouldAdd = NO;
                break;
            }
        }
    }
    return shouldAdd;
}

-(void)scrollToEndOffset{
    [self setContentOffset:CGPointMake(0, self.contentSize.height- self.bounds.size.height) animated:YES];
}

#pragma  mark ---textFieldShouldBeginEditing---
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
    //[self scrollToEndOffset];
    return  YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
    if(_tokenField.frame.size.height > self.frame.size.height) {
        [self scrollToEndOffset];
    }
    return YES;
}

//#pragma mark Property Overrides
//- (void) setChildFrames:(CGRect)frame {
//    CGFloat width = frame.size.width;
//    //[_resultsTable setFrame:((CGRect){_resultsTable.frame.origin, {width, _resultsTable.bounds.size.height}})];
//    [_tokenField setFrame:((CGRect){_tokenField.frame.origin, {width, _tokenField.bounds.size.height}})];
//}
//
//- (void)setFrame:(CGRect)frame {
//
//    [super setFrame:frame];
////
////    [self setChildFrames:frame];
////
////    [self updateContentSize];
////    [self setNeedsLayout];
//}

- (void)setContentOffset:(CGPoint)offset {
    NSLog(@"setContentOffset:%f",offset.y);
    [super setContentOffset:offset];
    [self setNeedsLayout];
}

- (NSArray *)tokenTitles {
    return _tokenField.tokenTitles;
}

- (void)setForcePickSearchResult:(BOOL)forcePickSearchResult
{
    _tokenField.forcePickSearchResult = forcePickSearchResult;
    _forcePickSearchResult = forcePickSearchResult;
}

- (void)setAlwaysShowSearchResult:(BOOL)alwaysShowSearchResult
{
    _tokenField.alwaysShowSearchResult = alwaysShowSearchResult;
    _alwaysShowSearchResult = alwaysShowSearchResult;
    if (_alwaysShowSearchResult) [self resultsForSearchString:_tokenField.text];
}

//#pragma mark Event Handling
//- (void)layoutSubviews {
//
//    [super layoutSubviews];
//
//    //[self afsdfadsfsdfas:self.frame];
//
//
////    CGFloat relativeFieldHeight = CGRectGetMaxY(_tokenField.frame) - self.contentOffset.y;
////    CGFloat newHeight = self.bounds.size.height - relativeFieldHeight;
////    if (newHeight > -1) [_resultsTable setFrame:((CGRect){_resultsTable.frame.origin, {_resultsTable.bounds.size.width, newHeight}})];
//}

- (void)updateContentSize {
    //[self setContentSize:CGSizeMake(self.bounds.size.width, CGRectGetMaxY(_contentView.frame) + 1)];
    CGFloat height = CGRectGetMaxY(_tokenField.frame);
    if(defaultHeight > height) {
        height = defaultHeight;
    }
    NSLog(@"updateContentSize:%f",CGRectGetMaxY(_tokenField.frame));
     [self setContentSize:CGSizeMake(self.bounds.size.width, height + 1)];
}

- (BOOL)canBecomeFirstResponder {
    return NO;
}

- (BOOL)becomeFirstResponder {
    return [_tokenField becomeFirstResponder];
}

- (BOOL)resignFirstResponder {
    return [_tokenField resignFirstResponder];
}

#pragma mark TableView Methods
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    if ([_tokenField.delegate respondsToSelector:@selector(tokenField:resultsTableView:heightForRowAtIndexPath:)]){
        return [_tokenField.delegate tokenField:_tokenField resultsTableView:tableView heightForRowAtIndexPath:indexPath];
    }
    
    return 44;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    if ([_tokenField.delegate respondsToSelector:@selector(tokenField:didFinishSearch:)]){
        [_tokenField.delegate tokenField:_tokenField didFinishSearch:_resultsArray];
    }
    
    return _resultsArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    id representedObject = [_resultsArray objectAtIndex:indexPath.row];
    
    if ([_tokenField.delegate respondsToSelector:@selector(tokenField:resultsTableView:cellForRepresentedObject:)]){
        return [_tokenField.delegate tokenField:_tokenField resultsTableView:tableView cellForRepresentedObject:representedObject];
    }
    
    static NSString * CellIdentifier = @"ResultsCell";
    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    NSString * subtitle = [self searchResultSubtitleForRepresentedObject:representedObject];
    
    if (!cell) cell = [[UITableViewCell alloc] initWithStyle:(subtitle ? UITableViewCellStyleSubtitle : UITableViewCellStyleDefault) reuseIdentifier:CellIdentifier];
    
    [cell.imageView setImage:[self searchResultImageForRepresentedObject:representedObject]];
    [cell.textLabel setText:[self searchResultStringForRepresentedObject:representedObject]];
    [cell.detailTextLabel setText:subtitle];
    
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
    id representedObject = [_resultsArray objectAtIndex:indexPath.row];
    TIToken * token = [[TIToken alloc] initWithTitle:[self displayStringForRepresentedObject:representedObject] representedObject:representedObject];
    [_tokenField addToken:token];
    
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    if (!_alwaysShowSearchResult) [self setSearchResultsVisible:NO];
}

#pragma mark TextField Methods

- (void)tokenFieldDidBeginEditing:(TITokenField *)field {
    if (!_alwaysShowSearchResult) [_resultsArray removeAllObjects];
    //[_resultsTable reloadData];
}

- (void)tokenFieldDidEndEditing:(TITokenField *)field {
    [self tokenFieldDidBeginEditing:field]; // 一直可以编辑
}

- (void)tokenFieldTextDidChange:(TITokenField *)field {
    [self resultsForSearchString:_tokenField.text];
    
    if (_forcePickSearchResult || _alwaysShowSearchResult) [self setSearchResultsVisible:YES];
    else [self setSearchResultsVisible:(_resultsArray.count > 0)];
}

- (void)tokenFieldFrameWillChange:(TITokenField *)field {
    
    //CGFloat tokenFieldBottom = CGRectGetMaxY(_tokenField.frame);
    //[_resultsTable setFrame:((CGRect){{_resultsTable.frame.origin.x, (tokenFieldBottom + 1)}, _resultsTable.bounds.size})];
}

- (void)tokenFieldFrameDidChange:(TITokenField *)field {
    [self updateContentSize];
    [self scrollToEndOffset];
}

#pragma mark Results Methods
- (NSString *)displayStringForRepresentedObject:(id)object {
    
    if ([_tokenField.delegate respondsToSelector:@selector(tokenField:displayStringForRepresentedObject:)]){
        return [_tokenField.delegate tokenField:_tokenField displayStringForRepresentedObject:object];
    }
    
    if ([object isKindOfClass:[NSString class]]){
        return (NSString *)object;
    }
    
    return [NSString stringWithFormat:@"%@", object];
}

- (NSString *)searchResultStringForRepresentedObject:(id)object {
    
    if ([_tokenField.delegate respondsToSelector:@selector(tokenField:searchResultStringForRepresentedObject:)]){
        return [_tokenField.delegate tokenField:_tokenField searchResultStringForRepresentedObject:object];
    }
    
    return [self displayStringForRepresentedObject:object];
}

- (NSString *)searchResultSubtitleForRepresentedObject:(id)object {
    
    if ([_tokenField.delegate respondsToSelector:@selector(tokenField:searchResultSubtitleForRepresentedObject:)]){
        return [_tokenField.delegate tokenField:_tokenField searchResultSubtitleForRepresentedObject:object];
    }
    
    return nil;
}

- (UIImage *)searchResultImageForRepresentedObject:(id)object {
    if ([_tokenField.delegate respondsToSelector:@selector(tokenField:searchResultImageForRepresentedObject:)]) {
        return [_tokenField.delegate tokenField:_tokenField searchResultImageForRepresentedObject:object];
    }
    
    return nil;
}


- (void)setSearchResultsVisible:(BOOL)visible {
    //[_resultsTable setHidden:!visible];
    [_tokenField setResultsModeEnabled:visible];
}

- (void)resultsForSearchString:(NSString *)searchString {
    
    // The brute force searching method.
    // Takes the input string and compares it against everything in the source array.
    // If the source is massive, this could take some time.
    // You could always subclass and override this if needed or do it on a background thread.
    // GCD would be great for that.
    
    [_resultsArray removeAllObjects];
    //[_resultsTable reloadData];
    
    searchString = [searchString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    
    if (searchString.length || _forcePickSearchResult || _alwaysShowSearchResult){
        
        if ([_tokenField.delegate respondsToSelector:@selector(tokenField:shouldUseCustomSearchForSearchString:)] && [_tokenField.delegate tokenField:_tokenField shouldUseCustomSearchForSearchString:searchString]) {
            if ([_tokenField.delegate respondsToSelector:@selector(tokenField:performCustomSearchForSearchString:withCompletionHandler:)]) {
                [_tokenField.delegate tokenField:_tokenField performCustomSearchForSearchString:searchString withCompletionHandler:^(NSArray *results) {
                    [self searchDidFinish:results];
                }];
            }
        } else {
            if (_shouldSearchInBackground) {
                [self performSelectorInBackground:@selector(performSearch:) withObject:searchString];
            } else {
                [self performSearch:searchString];
            }
        }
    }
}

- (void) performSearch:(NSString *)searchString {
    NSMutableArray * resultsToAdd = [[NSMutableArray alloc] init];
    [_sourceArray enumerateObjectsUsingBlock:^(id sourceObject, NSUInteger idx, BOOL *stop){
        
        NSString * query = [self searchResultStringForRepresentedObject:sourceObject];
        NSString * querySubtitle = [self searchResultSubtitleForRepresentedObject:sourceObject];
        if (!querySubtitle || !self->_searchSubtitles) {
            querySubtitle = @"";
        } else if (self->_subtitleIsPhoneNumber) {
            querySubtitle = [querySubtitle stringByReplacingOccurrencesOfString:@" " withString:@""];
        }
        
        if ([query rangeOfString:searchString options:NSCaseInsensitiveSearch].location != NSNotFound ||
            [querySubtitle rangeOfString:searchString options:NSCaseInsensitiveSearch].location != NSNotFound ||
            (self->_forcePickSearchResult && searchString.length == 0) ||
            (self->_alwaysShowSearchResult && searchString.length == 0)){
            
            __block BOOL shouldAdd = ![resultsToAdd containsObject:sourceObject];
            if (shouldAdd && !self->_showAlreadyTokenized){
                
                [self->_tokenField.tokens enumerateObjectsUsingBlock:^(TIToken * token, NSUInteger idx, BOOL *secondStop){
                    if ([token.representedObject isEqual:sourceObject]){
                        shouldAdd = NO;
                        *secondStop = YES;
                    }
                }];
            }
            
            if (shouldAdd) [resultsToAdd addObject:sourceObject];
        }
    }];
    
    [self searchDidFinish:resultsToAdd];
}

- (void)searchDidFinish:(NSArray *)results
{
    [_resultsArray addObjectsFromArray:results];
    if (_resultsArray.count > 0) {
        if (_shouldSortResults) {
            [_resultsArray sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
                return [[self searchResultStringForRepresentedObject:obj1] localizedCaseInsensitiveCompare:[self searchResultStringForRepresentedObject:obj2]];
            }];
        }
        [self performSelectorOnMainThread:@selector(reloadResultsTable) withObject:nil waitUntilDone:YES];
    }
}


-(void) reloadResultsTable {
    //[_resultsTable setHidden:NO];
    //[_resultsTable reloadData];
}

#pragma mark Other
- (NSString *)description {
    return [NSString stringWithFormat:@"<TITokenFieldView %p; Token count = %lu>", self, (unsigned long)self.tokenTitles.count];
}

- (void)dealloc {
    [self setDelegate:nil];
}

@end

//==========================================================
#pragma mark - TITokenField -
//==========================================================
NSString * const kTextEmpty = @"\u200B"; // Zero-Width Space
NSString * const kTextHidden = @"\u200D"; // Zero-Width Joiner

@interface TITokenFieldInternalDelegate ()
@property (nonatomic, weak) id <UITextFieldDelegate> delegate;
@property (nonatomic, weak) TITokenField * tokenField;
@end

@interface TITokenField ()
@property (nonatomic, readonly) CGFloat leftViewWidth;
@property (nonatomic, readonly) CGFloat rightViewWidth;
@property (weak, nonatomic, readonly) UIScrollView * scrollView;
@end

@interface TITokenField (Private)
- (void)setup;
- (CGFloat)layoutTokensInternal;
@end

@implementation TITokenField {
    id __weak delegate;
    TITokenFieldInternalDelegate * _internalDelegate;
    NSMutableArray * _tokens;
    CGPoint _tokenCaret;
    UILabel * _placeHolderLabel;
}
@synthesize delegate = delegate;
@synthesize editable = _editable;
@synthesize showShadow = _showShadow;
@synthesize resultsModeEnabled = _resultsModeEnabled;
@synthesize removesTokensOnEndEditing = _removesTokensOnEndEditing;
@synthesize numberOfLines = _numberOfLines;
@synthesize selectedToken = _selectedToken;
@synthesize tokenizingCharacters = _tokenizingCharacters;
@synthesize forcePickSearchResult = _forcePickSearchResult;
@synthesize alwaysShowSearchResult = _alwaysShowSearchResult;

#pragma mark Init
- (instancetype)initWithFrame:(CGRect)frame {
    
    if ((self = [super initWithFrame:frame])){
        [self setup];
    }
    
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    
    if ((self = [super initWithCoder:aDecoder])){
        [self setup];
    }
    
    return self;
}

- (void)setup {
    
    [self setBorderStyle:UITextBorderStyleNone];
    [self setFont:[UIFont systemFontOfSize:14]];
    [self setBackgroundColor:[UIColor whiteColor]];
    [self setAutocorrectionType:UITextAutocorrectionTypeNo];
    [self setAutocapitalizationType:UITextAutocapitalizationTypeNone];
    [self setContentVerticalAlignment:UIControlContentVerticalAlignmentTop];
    
    [self addTarget:self action:@selector(didBeginEditing) forControlEvents:UIControlEventEditingDidBegin];
    //[self addTarget:self action:@selector(didEndEditing) forControlEvents:UIControlEventEditingDidEnd];
    [self addTarget:self action:@selector(didChangeText) forControlEvents:UIControlEventEditingChanged];
    
    [self setPromptText:nil];
    [self setText:kTextEmpty];
    self.promptColor = [UIColor colorWithWhite:0.5 alpha:1];
    
    _internalDelegate = [[TITokenFieldInternalDelegate alloc] init];
    [_internalDelegate setTokenField:self];
    [super setDelegate:_internalDelegate];
    
    [self setShowShadow:YES];
    
    _tokens = [NSMutableArray array];
    _editable = YES;
    _removesTokensOnEndEditing = NO;
    _tokenizingCharacters = [NSCharacterSet characterSetWithCharactersInString:@","];
    _tokenLimit = -1;
}

#pragma mark Property Overrides
- (void)setFrame:(CGRect)frame {
    [super setFrame:frame];
    [self.layer setShadowPath:[[UIBezierPath bezierPathWithRect:self.bounds] CGPath]];
    [self layoutTokensAnimated:NO];
}

- (void)setShowShadow:(BOOL)showShadow {
    _showShadow = showShadow;
//    if (showShadow) {
//        [self.layer setShadowColor:[[UIColor blackColor] CGColor]];
//        [self.layer setShadowOpacity:0.6];
//        [self.layer setShadowRadius:12];
//    } else {
//        [self.layer setShadowColor:[[UIColor clearColor] CGColor]];
//    }
}

- (void)setText:(NSString *)text {
    [super setText:(text.length == 0 ? kTextEmpty : text)];
}

- (void)setFont:(UIFont *)font {
    [super setFont:font];
    
    if ([self.leftView isKindOfClass:[UILabel class]]){
        [self setPromptText:((UILabel *)self.leftView).text];
    }
}

- (void)setDelegate:(id<TITokenFieldDelegate>)del {
    delegate = del;
    [_internalDelegate setDelegate:delegate];
}

- (NSArray *)tokens {
    return [_tokens copy];
}

- (NSArray *)tokenTitles {
    
    NSMutableArray * titles = [NSMutableArray array];
    [_tokens enumerateObjectsUsingBlock:^(TIToken * token, NSUInteger idx, BOOL *stop){
        if (token.title) [titles addObject:token.title];
    }];
    return titles;
}

- (NSArray *)tokenObjects {
    
    NSMutableArray * objects = [NSMutableArray array];
    [_tokens enumerateObjectsUsingBlock:^(TIToken * token, NSUInteger idx, BOOL *stop){
        if (token.representedObject) [objects addObject:token.representedObject];
        else if (token.title) [objects addObject:token.title];
    }];
    return objects;
}

- (UIScrollView *)scrollView {
    return ([self.superview isKindOfClass:[UIScrollView class]] ? (UIScrollView *)self.superview : nil);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesMoved:touches withEvent:event];
}

- (BOOL)isTouchInside{
    return YES;
}

#pragma mark Event Handling
- (BOOL)becomeFirstResponder {
    return (_editable ? [super becomeFirstResponder] : NO);
}

- (void)didBeginEditing {
    if (_removesTokensOnEndEditing) {
        [_tokens enumerateObjectsUsingBlock:^(TIToken * token, NSUInteger idx, BOOL *stop){[self addTokenToView:token];}];
    }
}

- (void)didEndEditing {
    
    [_selectedToken setSelected:NO];
    _selectedToken = nil;
    
    [self tokenizeText];
    
    if (_removesTokensOnEndEditing){
        
        [_tokens enumerateObjectsUsingBlock:^(TIToken * token, NSUInteger idx, BOOL *stop){[token removeFromSuperview];}];
        
        NSString * untokenized = kTextEmpty;
        if (_tokens.count){
            
            NSArray * titles = self.tokenTitles;
            untokenized = [titles componentsJoinedByString:@", "];
            
            CGSize untokSize = [untokenized sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:14]}];
            CGFloat availableWidth = self.bounds.size.width - self.leftView.bounds.size.width - self.rightView.bounds.size.width;
            
            if (_tokens.count > 1 && untokSize.width > availableWidth){
                untokenized = [NSString stringWithFormat:@"%lu recipients", (unsigned long)titles.count];
            }
            
        }
        
        [self setText:untokenized];
    }
    
    [self setResultsModeEnabled:NO];
    if (_tokens.count < 1 && self.forcePickSearchResult) {
        [self becomeFirstResponder];
    }
}

- (void)didChangeText {
    if (!self.text.length)[self setText:kTextEmpty];
    [self showOrHidePlaceHolderLabel];
}

- (void) showOrHidePlaceHolderLabel {
    [_placeHolderLabel setHidden:!(([self.text isEqualToString:kTextEmpty]) && !_tokens.count)];
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    
    // Stop the cut, copy, select and selectAll appearing when the field is 'empty'.
    if (action == @selector(cut:) || action == @selector(copy:) || action == @selector(select:) || action == @selector(selectAll:))
        return ![self.text isEqualToString:kTextEmpty];
    
    return [super canPerformAction:action withSender:sender];
}

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
    
    if (_selectedToken && touch.view == self) [self deselectSelectedToken];
    return [super beginTrackingWithTouch:touch withEvent:event];
}



#pragma mark Token Handling
- (TIToken *)addTokenWithTitle:(NSString *)title {
    return [self addTokenWithTitle:title representedObject:nil];
}

- (TIToken *)addTokenWithTitle:(NSString *)title representedObject:(id)object {
    
    if (title.length){
        TIToken * token = [[TIToken alloc] initWithTitle:title representedObject:object font:self.font];
        [self addToken:token];
        return token;
    }
    
    return nil;
}

- (void)addTokensWithTitleList:(NSString *)titleList {
    if ([titleList length] > 0) {
        self.text = titleList;
        [self tokenizeText];
    }
}

- (void)addTokensWithTitleArray:(NSArray *)titleArray {
    for (NSString *title in titleArray) {
        [self addTokenWithTitle:title];
    }
}

- (void)addToken:(TIToken *)token {
    
    BOOL shouldAdd = YES;
    if ([delegate respondsToSelector:@selector(tokenField:willAddToken:)]){
        shouldAdd = [delegate tokenField:self willAddToken:token];
    }
    
    if (shouldAdd){
        
        //[self becomeFirstResponder];
        if (![_tokens containsObject:token]) {
            [_tokens addObject:token];
            
            if ([delegate respondsToSelector:@selector(tokenField:didAddToken:)]){
                [delegate tokenField:self didAddToken:token];
            }
        }
        
        [self addTokenToView:token];
        
    }
}

- (void) addTokenToView:(TIToken *)token
{
    [token addTarget:self action:@selector(tokenTouchDown:) forControlEvents:UIControlEventTouchDown];
    [token addTarget:self action:@selector(tokenTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
    [token addTarget:self action:@selector(touchUpOutside:) forControlEvents:UIControlEventTouchUpOutside];
    [self addSubview:token];
    [self layoutTokensAnimated:YES];
    [self showOrHidePlaceHolderLabel];
    [self setResultsModeEnabled:_alwaysShowSearchResult];
    [self deselectSelectedToken];
}

- (void)removeToken:(TIToken *)token {
    
    if (token == _selectedToken) [self deselectSelectedToken];
    
    BOOL shouldRemove = YES;
    if ([delegate respondsToSelector:@selector(tokenField:willRemoveToken:)]){
        shouldRemove = [delegate tokenField:self willRemoveToken:token];
    }
    
    if (shouldRemove){
        
        [token removeFromSuperview];
        [_tokens removeObject:token];
        [self layoutTokensAnimated:YES];
        
        if ([delegate respondsToSelector:@selector(tokenField:didRemoveToken:)]){
            [delegate tokenField:self didRemoveToken:token];
        }
        
        [self showOrHidePlaceHolderLabel];
        [self setResultsModeEnabled:_forcePickSearchResult || _alwaysShowSearchResult];
    }
}

// 修饰标题
- (NSString*)decoratorTitle:(NSString*)title{
    return title;
}

- (void)removeAllTokens {
    
    [_tokens enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(TIToken * token, NSUInteger idx, BOOL *stop) {
        [self removeToken:token];
    }];
    
    [self setText:@""];
}

- (void)selectToken:(TIToken *)token {
    
    BOOL selected = token.selected;
    
    if(selected) {
        // 取消选中
        [self deselectSelectedToken];
    } else {
        _selectedToken = token;
        [_selectedToken setSelected:YES];
        
        //[self becomeFirstResponder];
        [self setText:kTextHidden];
    }
}

- (void)deselectSelectedToken {
    
    [_selectedToken setSelected:NO];
    _selectedToken = nil;
    
    [self setText:kTextEmpty];
}

- (void)tokenizeText {
    
    __block BOOL textChanged = NO;
    __weak typeof(self) weakSelf = self;
    
    if (![self.text isEqualToString:kTextEmpty] && ![self.text isEqualToString:kTextHidden] && !_forcePickSearchResult){
        [[self.text componentsSeparatedByCharactersInSet:_tokenizingCharacters] enumerateObjectsUsingBlock:^(NSString * component, NSUInteger idx, BOOL *stop){
            component = [weakSelf decoratorTitle:component];
            
            
            NSArray *participle = [IStarTextTools participle:component];
            
            for (NSString * strTmp in participle) {
                [weakSelf addTokenWithTitle:[strTmp stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
            }
            
//            [weakSelf addTokenWithTitle:[component stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
            textChanged = YES;
        }];
    }
    
    if (textChanged) [self sendActionsForControlEvents:UIControlEventEditingChanged];
}

- (void)tokenTouchDown:(TIToken *)token {
    
    if (_selectedToken != token){
        [_selectedToken setSelected:NO];
        _selectedToken = nil;
    }
}

- (void)tokenTouchUpInside:(TIToken *)token {
    if (_editable) [self selectToken:token];
}

-(void)touchUpOutside:(TIToken *)token{
    // [self becomeFirstResponder];
}

//计算所有的
- (CGFloat)layoutTokensInternal {
    
    CGFloat topMargin = floor(self.font.lineHeight * 4 / 7);
    CGFloat leftMargin = self.leftViewWidth + 8;
    CGFloat hPadding = 8;
    CGFloat rightMargin = self.rightViewWidth + hPadding;
    CGFloat lineHeight = ceilf(self.font.lineHeight) + topMargin + 5;
    
    _numberOfLines = 1;
    _tokenCaret = (CGPoint){leftMargin, (topMargin - 1)};
    
    [_tokens enumerateObjectsUsingBlock:^(TIToken * token, NSUInteger idx, BOOL *stop){
        
        [token setFont:self.font];
        [token setMaxWidth:(self.bounds.size.width - rightMargin - (self->_numberOfLines > 1 ? hPadding : leftMargin))];
        
        if (token.superview){
            
            if (self->_tokenCaret.x + token.bounds.size.width + rightMargin > self.bounds.size.width){
                self->_numberOfLines++;
                self->_tokenCaret.x = (self->_numberOfLines > 1 ? hPadding : leftMargin);
                self->_tokenCaret.y += lineHeight;
            }
            
            [token setFrame:(CGRect){self->_tokenCaret, token.bounds.size}];
            self->_tokenCaret.x += token.bounds.size.width + 4;
            
            if (self.bounds.size.width - self->_tokenCaret.x - rightMargin < 50){
                self->_numberOfLines++;
                self->_tokenCaret.x = (self->_numberOfLines > 1 ? hPadding : leftMargin);
                self->_tokenCaret.y += lineHeight;
            }
        }
    }];
    
    return ceilf(_tokenCaret.y + lineHeight);
}

#pragma mark View Handlers
- (void)layoutTokensAnimated:(BOOL)animated {
    
    CGFloat newHeight = [self layoutTokensInternal];
    NSLog(@"layoutTokensAnimated-->:%f", newHeight);
    if (self.bounds.size.height != newHeight){
        

//        if(self.bounds.size.height >= newHeight) {
//            //[self setFrame:((CGRect){self.frame.origin, {self.bounds.size.width, newHeight}})];
//        } else {
//            [self setFrame:((CGRect){self.frame.origin, {self.bounds.size.width, newHeight}})];
//        }
        [self setFrame:((CGRect){self.frame.origin, {self.bounds.size.width, newHeight}})];
        [self sendActionsForControlEvents:(UIControlEvents)TITokenFieldControlEventFrameWillChange];
        [self sendActionsForControlEvents:(UIControlEvents)TITokenFieldControlEventFrameDidChange];
        
        
        // Animating this seems to invoke the triple-tap-delete-key-loop-problem-thing™
//        [UIView animateWithDuration:(animated && _editable ? 0.3 : 0) animations:^{
//            [self setFrame:((CGRect){self.frame.origin, {self.bounds.size.width, newHeight}})];
//            [self sendActionsForControlEvents:(UIControlEvents)TITokenFieldControlEventFrameWillChange];
//
//        } completion:^(BOOL complete){
//            if (complete) [self sendActionsForControlEvents:(UIControlEvents)TITokenFieldControlEventFrameDidChange];
//        }];
    }
}

- (void)setResultsModeEnabled:(BOOL)flag {
    [self setResultsModeEnabled:flag animated:YES];
}

- (void)setResultsModeEnabled:(BOOL)flag animated:(BOOL)animated {
    
    [self layoutTokensAnimated:animated];
    
    if (_resultsModeEnabled != flag){
        
        //Hide / show the shadow
        //[self.layer setMasksToBounds:!flag];
        
        UIScrollView * scrollView = self.scrollView;
        [scrollView setScrollsToTop:!flag];
        [scrollView setScrollEnabled:!flag];
        
        CGFloat offset = ((_numberOfLines == 1 || !flag) ? 0 : _tokenCaret.y - floor(self.font.lineHeight * 4 / 7) + 1);
        [scrollView setContentOffset:CGPointMake(0, self.frame.origin.y + offset) animated:animated];
    }
    
    _resultsModeEnabled = flag;
}

#pragma mark Left / Right view stuff
- (void)setPromptText:(NSString *)text {
    
    _promptText = text;
    if (text){
        
        UILabel * label = (UILabel *)self.leftView;
        if (!label || ![label isKindOfClass:[UILabel class]]){
            label = [[UILabel alloc] initWithFrame:CGRectZero];
            [self setLeftView:label];
            
            [self setLeftViewMode:UITextFieldViewModeAlways];
        }
        
        [label setTextColor:_promptColor];
        [label setText:text];
        [label setFont:[UIFont systemFontOfSize:(self.font.pointSize + 1)]];
        [label sizeToFit];
    }
    else
    {
        [self setLeftView:nil];
    }
    
    [self layoutTokensAnimated:YES];
}

- (void)setPromptColor:(UIColor *)promptColor
{
    _promptColor = promptColor;
    [self setPromptText:_promptText];
}

- (void)setPlaceholder:(NSString *)placeholder {
    
    if (placeholder){
        
        UILabel * label =  _placeHolderLabel;
        if (!label || ![label isKindOfClass:[UILabel class]]){
            label = [[UILabel alloc] initWithFrame:CGRectMake(_tokenCaret.x + 3, _tokenCaret.y + 2, self.rightView.bounds.size.width, self.rightView.bounds.size.height)];
            [label setTextColor:[UIColor colorWithWhite:0.75 alpha:1]];
            _placeHolderLabel = label;
            [self addSubview: _placeHolderLabel];
        }
        
        [label setText:placeholder];
        [label setFont:[UIFont systemFontOfSize:(self.font.pointSize + 1)]];
        [label sizeToFit];
    }
    else
    {
        [_placeHolderLabel removeFromSuperview];
        _placeHolderLabel = nil;
    }
    
    [self layoutTokensAnimated:YES];
}

#pragma mark Layout
- (CGRect)textRectForBounds:(CGRect)bounds {
    
    if ([self.text isEqualToString:kTextHidden]) return CGRectMake(0, -20, 0, 0);
    
    CGRect frame = CGRectOffset(bounds, _tokenCaret.x + 2, _tokenCaret.y + 3);
    frame.size.width -= (_tokenCaret.x + self.rightViewWidth + 10);
    
    return frame;
}

- (CGRect)editingRectForBounds:(CGRect)bounds {
    return [self textRectForBounds:bounds];
}

- (CGRect)placeholderRectForBounds:(CGRect)bounds {
    return [self textRectForBounds:bounds];
}

- (CGRect)leftViewRectForBounds:(CGRect)bounds {
    return ((CGRect){{8, ceilf(self.font.lineHeight * 4 / 7)}, self.leftView.bounds.size});
}

- (CGRect)rightViewRectForBounds:(CGRect)bounds {
    return ((CGRect){{bounds.size.width - self.rightView.bounds.size.width - 6,
        bounds.size.height - self.rightView.bounds.size.height - 6}, self.rightView.bounds.size});
}

- (CGFloat)leftViewWidth {
    
    if (self.leftViewMode == UITextFieldViewModeNever ||
        (self.leftViewMode == UITextFieldViewModeUnlessEditing && self.editing) ||
        (self.leftViewMode == UITextFieldViewModeWhileEditing && !self.editing)) return 0;
    
    return self.leftView.bounds.size.width;
}

- (CGFloat)rightViewWidth {
    
    if (self.rightViewMode == UITextFieldViewModeNever ||
        (self.rightViewMode == UITextFieldViewModeUnlessEditing && self.editing) ||
        (self.rightViewMode == UITextFieldViewModeWhileEditing && !self.editing)) return 0;
    
    return self.rightView.bounds.size.width;
}

#pragma mark Other
- (NSString *)description {
    return [NSString stringWithFormat:@"<TITokenField %p; prompt = \"%@\">", self, ((UILabel *)self.leftView).text];
}

- (void)dealloc {
    [self setDelegate:nil];
}

@end

//==========================================================
#pragma mark - TITokenFieldInternalDelegate -
//==========================================================
@implementation TITokenFieldInternalDelegate
@synthesize delegate = _delegate;
@synthesize tokenField = _tokenField;

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    
    if ([_delegate respondsToSelector:@selector(textFieldShouldBeginEditing:)]){
        return [_delegate textFieldShouldBeginEditing:textField];
    }
    
    return YES;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    

    //[self ttttbegin:textField];
    
    if ([_delegate respondsToSelector:@selector(textFieldDidBeginEditing:)]){
        [_delegate textFieldDidBeginEditing:textField];
    }
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    
    //[self ttttend:textField];
    
    if ([_delegate respondsToSelector:@selector(textFieldShouldEndEditing:)]){
        return [_delegate textFieldShouldEndEditing:textField];
    }
    
    return YES;
}


-(void) ttttbegin:(UITextField*)textField{
    UIScrollView *wrap = [[UIScrollView alloc] initWithFrame:textField.frame];
    [textField.superview addSubview:wrap];
    [textField setFrame:CGRectMake(0, 0, textField.frame.size.width, textField.frame.size.height)];
    [wrap addSubview: textField];
}

-(void)ttttend:(UITextField*)textField{
    UIScrollView *wrap = (UIScrollView *)textField.superview;
    [textField setFrame:CGRectMake(wrap.frame.origin.x, wrap.frame.origin.y, wrap.frame.size.width, textField.frame.size.height)];
    [wrap.superview addSubview:textField];
    [wrap removeFromSuperview];
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    
    if ([_delegate respondsToSelector:@selector(textFieldDidEndEditing:)]){
        [_delegate textFieldDidEndEditing:textField];
    }
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    
    if (_tokenField.tokens.count && [string isEqualToString:@""] && [_tokenField.text isEqualToString:kTextEmpty]){
        [_tokenField selectToken:[_tokenField.tokens lastObject]];
        return NO;
    }
    
    if ([textField.text isEqualToString:kTextHidden]){
        [_tokenField removeToken:_tokenField.selectedToken];
        return (![string isEqualToString:@""]);
    }
    
    if ([string rangeOfCharacterFromSet:_tokenField.tokenizingCharacters].location != NSNotFound && !_tokenField.forcePickSearchResult){
        [_tokenField tokenizeText];
        return NO;
    }
    
    if ([_delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]){
        return [_delegate textField:textField shouldChangeCharactersInRange:range replacementString:string];
    }
    
    if (_tokenField.tokenLimit!=-1 &&
        [_tokenField.tokens count] >= _tokenField.tokenLimit) {
        return NO;
    }
    
    return YES;
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    
    [_tokenField tokenizeText];
    
    if ([_delegate respondsToSelector:@selector(textFieldShouldReturn:)]){
        return [_delegate textFieldShouldReturn:textField];
    }
    
    return YES;
}

- (BOOL)textFieldShouldClear:(UITextField *)textField {
    
    if ([_delegate respondsToSelector:@selector(textFieldShouldClear:)]){
        return [_delegate textFieldShouldClear:textField];
    }
    
    return YES;
}

@end


//==========================================================
#pragma mark - TIToken -
//==========================================================

CGFloat const hTextPadding = 14;
CGFloat const vTextPadding = 8;
CGFloat const kDisclosureThickness = 2.5;
NSLineBreakMode const kLineBreakMode = NSLineBreakByTruncatingTail;

@interface TIToken (Private)
CGPathRef CGPathCreateTokenPath(CGSize size, BOOL innerPath);
CGPathRef CGPathCreateDisclosureIndicatorPath(CGPoint arrowPointFront, CGFloat height, CGFloat thickness, CGFloat * width);
- (BOOL)getTintColorRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha;
@end

@implementation TIToken
@synthesize title = _title;
@synthesize representedObject = _representedObject;
@synthesize font = _font;
@synthesize tintColor = _tintColor;
@synthesize textColor = _textColor;
@synthesize highlightedTextColor = _highlightedTextColor;
@synthesize accessoryType = _accessoryType;
@synthesize maxWidth = _maxWidth;

#pragma mark Init
- (instancetype)initWithTitle:(NSString *)aTitle {
    return [self initWithTitle:aTitle representedObject:nil];
}

- (instancetype)initWithTitle:(NSString *)aTitle representedObject:(id)object {
    return [self initWithTitle:aTitle representedObject:object font:[UIFont systemFontOfSize:14]];
}

- (instancetype)initWithTitle:(NSString *)aTitle representedObject:(id)object font:(UIFont *)aFont {
    
    if ((self = [super init])){
        
        _title = [aTitle copy];
        _representedObject = object;
        
        _font = aFont;
        _tintColor = [TIToken istarStcikyColor];//[TIToken blueTintColor];
        _textColor = IStarRGBAllColor(0x5090F1);
        _highlightedTextColor = [UIColor whiteColor];
        
        _accessoryType = TITokenAccessoryTypeWords;
        _maxWidth = 200;
        
        [self setBackgroundColor:[UIColor clearColor]];
        [self sizeToFit];
    }
    
    return self;
}

- (void)setTextColor:(UIColor *)textColor{
    _textColor = textColor;
}

#pragma mark Property Overrides
- (void)setHighlighted:(BOOL)flag {
    
    if (self.highlighted != flag){
        [super setHighlighted:flag];
        [self setNeedsDisplay];
    }
}

- (void)setSelected:(BOOL)flag {
    
    if (self.selected != flag){
        [super setSelected:flag];
        [self setNeedsDisplay];
    }
}

- (void)setTitle:(NSString *)newTitle {
    
    if (newTitle){
        _title = [newTitle copy];
        [self sizeToFit];
        [self setNeedsDisplay];
    }
}

- (void)setFont:(UIFont *)newFont {
    
//    if (!newFont) newFont = [UIFont systemFontOfSize:14];
//
//    if (_font != newFont){
//        _font = newFont;
//        [self sizeToFit];
//        [self setNeedsDisplay];
//    }
    _font = [UIFont systemFontOfSize:14];
}

- (void)setTintColor:(UIColor *)newTintColor {
    
    if (!newTintColor) newTintColor = [TIToken blueTintColor];
    
    if (_tintColor != newTintColor){
        _tintColor = newTintColor;
        [self setNeedsDisplay];
    }
}

- (void)setAccessoryType:(TITokenAccessoryType)type {
    
    if (_accessoryType != type){
        _accessoryType = type;
        [self sizeToFit];
        [self setNeedsDisplay];
    }
}

- (void)setMaxWidth:(CGFloat)width {
    
    if (_maxWidth != width){
        _maxWidth = width;
        [self sizeToFit];
        [self setNeedsDisplay];
    }
}

#pragma Tint Color Convenience

+ (UIColor *)blueTintColor {
    return [UIColor colorWithRed:0.216 green:0.373 blue:0.965 alpha:1];
}

+ (UIColor *)redTintColor {
    return [UIColor colorWithRed:1 green:0.15 blue:0.15 alpha:1];
}

+ (UIColor *)greenTintColor {
    return [UIColor colorWithRed:0.333 green:0.741 blue:0.235 alpha:1];
}

+ (UIColor *)istarStcikyColor{
    return [UIColor colorWithRed:80/255.0 green:144/255.0 blue:241/255.0 alpha:0.7];
}

+ (UIColor *)istarWordColor{
    return [UIColor whiteColor];
}




#pragma mark Layout
- (CGSize)sizeThatFits:(CGSize)size {
    
    CGFloat accessoryWidth = 1;
    
    if (_accessoryType == TITokenAccessoryTypeDisclosureIndicator){
        CGPathRelease(CGPathCreateDisclosureIndicatorPath(CGPointZero, _font.pointSize, kDisclosureThickness, &accessoryWidth));
        accessoryWidth += floorf(hTextPadding / 2);
    }
    
    NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    paragraphStyle.lineBreakMode = kLineBreakMode;
    
    CGRect titleFrame = [_title boundingRectWithSize:(CGSize){(_maxWidth - hTextPadding - accessoryWidth), CGFLOAT_MAX}
                                             options:NSStringDrawingUsesLineFragmentOrigin
                                          attributes:@{
                                                       NSFontAttributeName: _font,
                                                       NSParagraphStyleAttributeName: paragraphStyle
                                                       }
                                             context:nil];
    CGFloat height = floorf(titleFrame.size.height + vTextPadding);
    
    return (CGSize){MAX(floorf(titleFrame.size.width + hTextPadding + accessoryWidth), height - 3), height};
}

-(BOOL)isTokenSelected{
    return (self.selected || self.highlighted);
}

#pragma mark Drawing
- (void)drawRect:(CGRect)rect {
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // Draw the outline.
    CGContextSaveGState(context);
    CGPathRef outlinePath = CGPathCreateTokenPath(self.bounds.size, NO);
    CGContextAddPath(context, outlinePath);
    CGPathRelease(outlinePath);
    
    //BOOL drawHighlighted = [self isTokenSelected];
    
    CGFloat red = 1;
    CGFloat green = 1;
    CGFloat blue = 1;
    CGFloat alpha = 0.4;
    [self getTintColorRed:&red green:&green blue:&blue alpha:&alpha];
    
    if ([self isTokenSelected]){
        red = 80/255.0;
        green = 144/255.0;
        blue = 241/255.0;
        CGContextSetFillColor(context, (CGFloat[4]){red, green, blue, 1});
        CGContextFillPath(context);
    }
    else
    {
        red = 80/255.0;
        green = 144/255.0;
        blue = 241/255.0;
        CGContextSetFillColor(context, (CGFloat[4]){red, green, blue, 0.1});
        CGContextFillPath(context);
    }
    
    if(_accessoryType == TITokenAccessoryTypeWords) {
        if(![self isTokenSelected]) {
            [self drawRectInner:rect context:context];
        }
    } else {
//        CGFloat locations[2] = {0, ([self isTokenSelected] ? 0.9 : 0.6)};
//        CGFloat highlightedComp[8] = {red, green, blue, 0.7, red, green, blue, 1};
//        CGFloat nonHighlightedComp[8] = {red, green, blue, 0.15, red, green, blue, 0.1};
//
//        CGPoint endPoint = CGPointMake(0, self.bounds.size.height);
//        CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
//        CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, ([self isTokenSelected] ? highlightedComp : nonHighlightedComp), locations, 2);
//        CGContextDrawLinearGradient(context, gradient, CGPointZero, endPoint, 0);
//        CGGradientRelease(gradient);
//        CGColorSpaceRelease(colorspace);
    }
    [self drawRectTitle:rect context:context];
}

-(void)drawRectInner:(CGRect)rect context:(CGContextRef)context{
        CGPathRef innerPath = CGPathCreateTokenPath(self.bounds.size, YES);
    
        // Draw a white background so we can use alpha to lighten the inner gradient
        CGContextSaveGState(context);
        CGContextAddPath(context, innerPath);
        CGContextSetFillColor(context, (CGFloat[4]){1, 1, 1, 1});
        CGContextFillPath(context);
        CGContextRestoreGState(context);
    
        // Draw the inner gradient.
        CGContextSaveGState(context);
        CGContextAddPath(context, innerPath);
        CGPathRelease(innerPath);
        CGContextClip(context);
}


-(void)drawRectTitle:(CGRect)rect context:(CGContextRef)context{
    CGContextRestoreGState(context);
    CGFloat accessoryWidth = 0;
    NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
    paragraphStyle.lineBreakMode = kLineBreakMode;
    NSDictionary *attributes = @{
                                 NSFontAttributeName: _font,
                                 NSParagraphStyleAttributeName: paragraphStyle,
                                 NSForegroundColorAttributeName:([self isTokenSelected] ? _highlightedTextColor : _textColor)
                                 };
    
    CGRect titleFrame = [_title boundingRectWithSize:(CGSize){(_maxWidth - hTextPadding - accessoryWidth), CGFLOAT_MAX}
                                             options:NSStringDrawingUsesLineFragmentOrigin
                                          attributes:attributes
                                             context:nil];
    CGFloat vPadding = floor((self.bounds.size.height - titleFrame.size.height) / 2);
    CGFloat titleWidth = ceilf(self.bounds.size.width - hTextPadding - accessoryWidth);
    CGRect textBounds = CGRectMake(floorf(hTextPadding / 2), vPadding, titleWidth, floorf(self.bounds.size.height - (vPadding * 2)));
    
    CGContextSetFillColorWithColor(context, ([self isTokenSelected]  ? _highlightedTextColor : _textColor).CGColor); //这行不管用
    //CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
    [_title drawInRect:textBounds withAttributes:attributes];
}


CGPathRef CGPathCreateTokenPath(CGSize size, BOOL innerPath) {
    
//    CGMutablePathRef path = CGPathCreateMutable();
//    CGFloat arcValue = (size.height / 2) - 1;
//    CGFloat radius = arcValue - (innerPath ? (1 / [[UIScreen mainScreen] scale]) : 0);
//    CGPathAddArc(path, NULL, arcValue, arcValue, radius, (M_PI / 2), (M_PI * 3 / 2), NO);
//    CGPathAddArc(path, NULL, size.width - arcValue, arcValue, radius, (M_PI  * 3 / 2), (M_PI / 2), NO);
//    CGPathCloseSubpath(path);
    CGFloat innerWidth = 1;
    
    CGFloat width = innerPath ?  (size.width - 2*innerWidth): size.width;
    CGFloat height = innerPath ? (size.height - 2*innerWidth) : size.height;

    //创建用于转移坐标的Transform，这样我们不用按照实际显示做坐标计算===>偏移到某一个位置
    CGAffineTransform transform = CGAffineTransformMakeTranslation(innerPath? innerWidth: 0, innerPath? innerWidth: 0);
    //创建CGMutablePathRef
    CGMutablePathRef path = CGPathCreateMutable();
    
    
    //半径为30
    CGFloat radius = 4;
    //初始点为(0, 0)
    CGPathMoveToPoint(path, &transform, 0, 0);
    //右上角和右下角两个点，画出半个圆角
    CGPathAddArcToPoint(path, &transform, width, 0, width, height, radius);
    //右下角和左下角两个点，画出另外半个圆角
    CGPathAddArcToPoint(path, &transform, width, height, 0, height, radius);
    CGPathAddArcToPoint(path, &transform, 0, height, 0, 0, radius);
    CGPathAddArcToPoint(path, &transform, 0, 0, width, 0, radius);
    CGPathCloseSubpath(path);
    return path;
}

//CGPathRef CGPathCreateTokenPath() {
//    CGMutablePathRef path = CGPathCreateMutable();
//
//    return path;
//}

CGPathRef CGPathCreateDisclosureIndicatorPath(CGPoint arrowPointFront, CGFloat height, CGFloat thickness, CGFloat * width) {
    
    thickness /= cosf(M_PI / 4);
    
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, arrowPointFront.x, arrowPointFront.y);
    
    CGPoint bottomPointFront = CGPointMake(arrowPointFront.x - (height / (2 * tanf(M_PI / 4))), arrowPointFront.y - height / 2);
    CGPathAddLineToPoint(path, NULL, bottomPointFront.x, bottomPointFront.y);
    
    CGPoint bottomPointBack = CGPointMake(bottomPointFront.x - thickness * cosf(M_PI / 4),  bottomPointFront.y + thickness * sinf(M_PI / 4));
    CGPathAddLineToPoint(path, NULL, bottomPointBack.x, bottomPointBack.y);
    
    CGPoint arrowPointBack = CGPointMake(arrowPointFront.x - thickness / cosf(M_PI / 4), arrowPointFront.y);
    CGPathAddLineToPoint(path, NULL, arrowPointBack.x, arrowPointBack.y);
    
    CGPoint topPointFront = CGPointMake(bottomPointFront.x, arrowPointFront.y + height / 2);
    CGPoint topPointBack = CGPointMake(bottomPointBack.x, topPointFront.y - thickness * sinf(M_PI / 4));
    
    CGPathAddLineToPoint(path, NULL, topPointBack.x, topPointBack.y);
    CGPathAddLineToPoint(path, NULL, topPointFront.x, topPointFront.y);
    CGPathAddLineToPoint(path, NULL, arrowPointFront.x, arrowPointFront.y);
    
    if (width) *width = (arrowPointFront.x - topPointBack.x);
    return path;
}

- (BOOL)getTintColorRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha {
    
    CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(CGColorGetColorSpace(_tintColor.CGColor));
    const CGFloat * components = CGColorGetComponents(_tintColor.CGColor);
    
    if (colorSpaceModel == kCGColorSpaceModelMonochrome || colorSpaceModel == kCGColorSpaceModelRGB){
        
        if (red) *red = components[0];
        if (green) *green = (colorSpaceModel == kCGColorSpaceModelMonochrome ? components[0] : components[1]);
        if (blue) *blue = (colorSpaceModel == kCGColorSpaceModelMonochrome ? components[0] : components[2]);
        if (alpha) *alpha = (colorSpaceModel == kCGColorSpaceModelMonochrome ? components[1] : components[3]);
        
        return YES;
    }
    
    return NO;
}

#pragma mark Other
- (NSString *)description {
    return [NSString stringWithFormat:@"<TIToken %p; title = \"%@\"; representedObject = \"%@\">", self, _title, _representedObject];
}


@end
